/*
 * Copyright (C) 2010, Funcom AS, All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  @authors
 *  Svein Gunnar Larsen <sveingunnarlarsen@gmail.com>
 *  Erik Thune Lund <culex.eriklund@gmail.com>
 *  Michel Krohn-Dale <kronicz@gmail.com>
 */

package com.funcom.peeler.properties;

import com.funcom.peeler.BorderProperty;
import com.funcom.peeler.PeelStyleSheet;
import com.funcom.peeler.UpdateCont;
import com.funcom.peeler.WorkBench;
import com.funcom.peeler.adapter.KeyAndMouseAdapter;
import com.funcom.peeler.peelable.PeelComponent;
import com.funcom.peeler.utils.SwingMessages;
import com.jmex.bui.Rule;
import com.jmex.bui.property.BackgroundProperty;
import com.jmex.bui.property.FontProperty;
import com.jmex.bui.property.IconProperty;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.*;

import static com.funcom.peeler.UpdateCont.get;

public class StylesAndRules extends UpdateableProperties {

    JList styleList;
    JTextArea styleRule;
    JButton setStyle;
    JButton clearRule;
    JButton deleteRule;

    boolean updateList = false;
    boolean updateRule = false;

    PeelStyleSheet currentStyleSheet;
    Set<String> previousRules = new HashSet<String>();
    Set<PeelComponent> allComp;

    public StylesAndRules(JList styleList, JTextArea styleRule, JButton setStyle, JButton clearRule, JButton deleteRule) {
        this.styleList  = styleList;
        this.styleRule  = styleRule;
        this.setStyle   = setStyle;
        this.clearRule  = clearRule;
        this.deleteRule = deleteRule;

        styleList.setModel(new DefaultListModel());

        initListeners();
    }

    public void update() {

        if (updateList) {
            updateStyleList();
            updateList = false;
        }
        if (updateRule) {
            setStyleRules();
            updateRule = false;
        }
        fields_cleared = false;
    }

    public void needUpdate( WorkBench workBench,
                            Set<PeelComponent> allComp,
                            Set<PeelComponent> selectedComps,
                            PeelComponent main_selected,
                            PropertiesFrame thisFrame ) {
        this.allComp = allComp;

        if (workBench.getWorkBenchStyle() != currentStyleSheet) {
            currentStyleSheet = workBench.getWorkBenchStyle();

            for (PeelComponent aComp : allComp) {
                if (currentStyleSheet.noDefaultStyle( aComp.getComponent() )) {
                    updateList = true;
                }
            }
            updateList = true;
        }

        if (selectedComp != main_selected) {
            selectedComp = main_selected;
            updateList = true;
        }

        if (selectedComp != null) {

            if (currentStyleSheet.noDefaultStyle( selectedComp.getComponent() )) {
                updateList = true;
            }
        }

        if (currentStyleSheet._rules.size() != previousRules.size()) {
            updateList = true;
        }

        Set<String> styles = currentStyleSheet.getRules().keySet();

        for (String aStyle : styles) {
            if (!previousRules.contains(aStyle)) {
                updateList = true;
            }
        }

        if (updateList || updateRule) {
            wantUpdate = true;
        }
    }

    public void applyChange( PeelComponent component, PropertiesFrame updater ) {

        switch (change) {
            case CHANGE_STYLE: {

                String style = (String)styleList.getSelectedValue();
                UpdateCont.get().invalidateComponent(component, true, style);

                break;
            }
            case CLEAR_RULE: {

                String style = (String)styleList.getSelectedValue();

                if (!currentStyleSheet.clearStyle( style ) ) {
                    SwingUtilities.invokeLater( new Runnable() {
                        public void run() {
                            SwingMessages.textError(SwingMessages.CLEAR_ROOT);
                        }
                    });
                } else {
                    setStyleRules();
                    get().invalidateAll();
                }

                break;
            }
            case DELETE_RULE: {

                String style = (String)styleList.getSelectedValue();

                if (! currentStyleSheet.removeStyle( style, allComp ) ) {
                    SwingUtilities.invokeLater( new Runnable() {
                        public void run() {
                            SwingMessages.textError(SwingMessages.ERROR_DELETE);
                        }
                    });                 
                } else {
                    wantUpdate = true;
                }
            }
        }
    }

    public void clear() {
        styleRule.setText("");
    }

    private void updateStyleList() {

        // Populate the style list.
        ((DefaultListModel) styleList.getModel()).clear();
        previousRules.clear();

        Collection<String> styleSet = currentStyleSheet.getRules().keySet();
        final String[] stringList = new String[ styleSet.size() ];

        int i = 0;
        for (String aStyle : styleSet) {
            stringList[i++] = aStyle;
            previousRules.add(aStyle);
        }

        Arrays.sort(stringList);

        for (String aStringList : stringList) {
            if (aStringList.equals("window")) continue;
            ((DefaultListModel) styleList.getModel()).addElement(aStringList);
        }

        if (selectedComp != null) {
            String style = selectedComp.getComponent().getStyleClass();
            styleList.setSelectedValue(style, false);
        } else {
            styleList.clearSelection();
        }
    }

    private void setStyleRules() {

        String allRules = "";

        String selectedStyle = (String) styleList.getSelectedValue();
        Rule styleClassProp = get().getStyleClassProp(selectedStyle);
        Map<String, Object> propMap;

        try {
            propMap = styleClassProp.properties;
        } catch (NullPointerException e) {
            return;
        }

        Set<String> propSet = propMap.keySet();

        for (String aPropSet : propSet) {
            Object value = propMap.get(aPropSet);

            if (value != null) {
                String ruleValue;

                if (value instanceof BackgroundProperty) {
                    ruleValue = "\n" + "TYPE:  " + ((BackgroundProperty) value).type + "\n";
                    if (((BackgroundProperty) value).type.equals("image")) {
                        ruleValue += "PATH:  " + ((BackgroundProperty) value).ipath + "\n"
                                + "SCALE: " + ((BackgroundProperty) value).scaleMode + "\n";
                    } else if (((BackgroundProperty) value).type.equals("solid")) {
                        ruleValue += "COLOR" + ((BackgroundProperty) value).color + "\n";
                    }
                } else if (value instanceof IconProperty) {
                    ruleValue = "\n" + "TYPE: " + ((IconProperty) value).type + "\n";
                    if (((IconProperty) value).type.equals("image")) {
                        ruleValue += "PATH: " + ((IconProperty) value).ipath + "\n";
                    }
                } else if (value instanceof FontProperty) {
                    ruleValue = "\n" + "FAMILY: " + ((FontProperty) value).family + "\n"
                            + "STYLE: " + ((FontProperty) value).style + "\n"
                            + "SIZE: " + ((FontProperty) value).size + "\n";
                } else if (value instanceof BorderProperty) {
                    continue;
                } else {
                    ruleValue = value.toString() + "\n";
                }

                allRules += aPropSet + ": " + ruleValue + "\n";
            } else {
                allRules = "";
            }
        }
        styleRule.setText("" + allRules);
    }

    protected void initListeners() {

        StyleListener listener = new StyleListener();

        styleList.addMouseListener(listener);
        styleList.addKeyListener(listener);

        setStyle.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                change = ChangeProp.CHANGE_STYLE;
            }
        });

        clearRule.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                change = ChangeProp.CLEAR_RULE;
            }
        });

        deleteRule.addActionListener(new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                change = ChangeProp.DELETE_RULE;
            }
        });
    }

    private class StyleListener extends KeyAndMouseAdapter {
        public void keyPressed(KeyEvent e) {
            updateRule = true;
        }
        public void mousePressed(MouseEvent e) {
            updateRule = true;
        }
    }
}
